package com.borealis.common.utils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 参数工具类
 *
 * @author yaoweixin
 * @date 2019/01/09
 */
@Slf4j
public class DataUtils {

  /**
   * 解析为List格式
   */
  public static List<Object> parseList(Object... objects) {
    List<Object> dataObj = Lists.newArrayList();
    for (Object key : objects) {
      dataObj.add(key.toString());
    }
    return dataObj;
  }

  /**
   * 解析为Map格式
   */
  public static Map<String, Object> parseMap(Object... objects) {
    Map<String, Object> dataObj = Maps.newHashMap();
    for (int i = 0; i < objects.length; i++) {
      Object key = objects[i];
      i++;
      if (i >= objects.length) {
        break;
      }
      Object val = objects[i];
      dataObj.put(key.toString(), val);
    }
    return dataObj;
  }

  /**
   * 解析为Linked Map格式
   */
  public static Map<String, Object> parseLinkedMap(Object... objects) {
    Map<String, Object> dataObj = Maps.newLinkedHashMap();
    for (int i = 0; i < objects.length; i++) {
      Object key = objects[i];
      i++;
      if (i >= objects.length) {
        break;
      }
      Object val = objects[i];
      dataObj.put(key.toString(), val);
    }
    return dataObj;
  }

  /**
   * 往Map里放入值
   */
  public static void addToMap(Map<String, Object> map, Object key, Object val) {
    map.put(key.toString(), val);
  }

  /**
   * Map转成URL形式参数
   */
  public static String mapToUrlParam(Map<String, Object> param) {
    List<String> list = Lists.newArrayList();
    list.addAll(param.keySet());
    Collections.sort(list);

    StringBuilder signParam = new StringBuilder();
    for (String key : list) {
      signParam.append(key);
      signParam.append("=");
      signParam.append(param.get(key).toString());
      signParam.append("&");
    }
    int lasts = signParam.lastIndexOf("&");
    return StringUtils.substring(signParam.toString(), 0, lasts);
  }

  /**
   * 对象属性数据转为MAP
   *
   * @param object 对象
   * @return 包含对象所有属性的MAP
   */
  public static Map<String, Object> object2Map(Object object) {
    Map<String, Object> result = Maps.newHashMap();
    Class tempClass = object.getClass();
    while (tempClass != null) {
      // 获得类的的属性名 数组
      Field[] fields = tempClass.getDeclaredFields();
      try {
        for (Field field : fields) {
          field.setAccessible(true);
          result.put(field.getName(), field.get(object));
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
      tempClass = tempClass.getSuperclass();
    }
    return result;
  }

  /**
   * 获取对象值
   *
   * @param object    对象
   * @param fieldName 字段名
   * @return 字段值
   */
  public static Object getObjectValue(Object object, String fieldName) {
    String firstLetter = fieldName.substring(0, 1).toUpperCase();
    String getter = "get" + firstLetter + fieldName.substring(1);
    Method method;
    Object value;
    try {
      method = object.getClass().getMethod(getter);
      value = method.invoke(object);
      return value;
    } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
      log.debug("getObjectValue error: ", e);
    }
    return null;
  }

  public static class MapKeyComparator implements Comparator<String> {

    @Override
    public int compare(String o1, String o2) {
      return o1.compareTo(o2);
    }
  }

  /**
   * 使用 Map按key进行排序
   *
   * @param map 待排序的数据
   * @return 排序后的数据
   */
  public static Map<String, Object> sortMapByKey(Map<String, Object> map) {
    if (map == null || map.isEmpty()) {
      return null;
    }
    Map<String, Object> sortMap = new TreeMap<>(new MapKeyComparator());
    sortMap.putAll(map);
    return sortMap;
  }

  public static Map<String, String> xmlToMap(String strXml) {
    InputStream stream = null;
    try {
      Map<String, String> data = Maps.newHashMap();
      DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
      stream = new ByteArrayInputStream(strXml.getBytes(StandardCharsets.UTF_8));
      org.w3c.dom.Document doc = documentBuilder.parse(stream);
      doc.getDocumentElement().normalize();
      NodeList nodeList = doc.getDocumentElement().getChildNodes();
      for (int idx = 0; idx < nodeList.getLength(); ++idx) {
        Node node = nodeList.item(idx);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
          org.w3c.dom.Element element = (org.w3c.dom.Element) node;
          data.put(element.getNodeName(), element.getTextContent());
        }
      }
      return data;
    } catch (Exception e) {
      log.error("xmlToMap.error:", e);
      return null;
    } finally {
      if (stream != null) {
        try {
          stream.close();
        } catch (IOException e) {
          log.error("xmlToMap.close.error:", e);
        }
      }
    }
  }
}